stx_path = './stx/'
preprocessor_path = stx_path + 'preprocessor/'
preprocessor_file_name = stx_path + 'preprocessor.hpp'
generate_STX_PP_FOR_EACH_i = 0
generate_STX_PP_FOR_EACH_I_i = 0
max_args = 256
container_max_size = 256
sequence_max_size = 256
for_each_size = 255
num_nested_seq_for_each_i = 4
main_header_guard = 'STX_PREPROCESSOR_HPP'

import os, shutil

def write_header_guard_begin(file, header_guard):
    file.write('#ifndef {0}\n'.format(header_guard))
    file.write('#define {0}\n\n'.format(header_guard))

def write_header_guard_end(file, header_guard):
    file.write('#endif // {0}\n'.format(header_guard))

try:
    shutil.rmtree(preprocessor_path, True)
except:
    pass

try:
    os.remove(preprocessor_file_name)
except:
    pass

dir_list = [
    'preprocessor',
    'preprocessor/arithmetic',
    'preprocessor/seq',
    'preprocessor/tuple'
]

for i in range(len(dir_list)):
    dir_list[i] = stx_path + dir_list[i]

for d in dir_list:
    try:
        os.mkdir(d)
    except:
        pass

f = open(preprocessor_file_name, 'w')

write_header_guard_begin(f, main_header_guard)

f.write("""\
// STX_PP_NOT_DEFINED - this macro is not defined, it's purpose is not to be a macro.

#include <stx/preprocessor/arithmetic.hpp>
#include <stx/preprocessor/cat.hpp>
#include <stx/preprocessor/expand.hpp>
#include <stx/preprocessor/seq.hpp>
#include <stx/preprocessor/stringize.hpp>
#include <stx/preprocessor/tuple.hpp>
#include <stx/preprocessor/wstringize.hpp>

""")

f = open(preprocessor_path + 'cat.hpp', 'w')
header_guard = 'STX_PREPROCESSOR_CAT_HPP'
write_header_guard_begin(f, header_guard)
f.write("""\
#define STX_PP_CAT(x, y) STX_PP_CAT_IMPL(x, y)
#define STX_PP_CAT_IMPL(x, y) x ## y

""")
write_header_guard_end(f, header_guard)

f = open(preprocessor_path + 'stringize.hpp', 'w')
header_guard = 'STX_PREPROCESSOR_STRINGIZE_HPP'
write_header_guard_begin(f, header_guard)
f.write("""\
#define STX_PP_STRINGIZE(x) STX_PP_STRINGIZE_IMPL(x)
#define STX_PP_STRINGIZE_IMPL(x) #x

""")
write_header_guard_end(f, header_guard)

f = open(preprocessor_path + 'wstringize.hpp', 'w')
header_guard = 'STX_PREPROCESSOR_WSTRINGIZE_HPP'
write_header_guard_begin(f, header_guard)
f.write("""\
#define STX_PP_WSTRINGIZE(x) STX_PP_WSTRINGIZE_IMPL(x)
#define STX_PP_WSTRINGIZE_IMPL(x) STX_PP_WSTRINGIZE_IMPL2(#x)
#define STX_PP_WSTRINGIZE_IMPL2(x) L ## str

""")
write_header_guard_end(f, header_guard)

f = open(preprocessor_path + 'expand.hpp', 'w')
header_guard = 'STX_PREPROCESSOR_EXPAND_HPP'
write_header_guard_begin(f, header_guard)
f.write("""\
#define STX_PP_EXPAND(x) STX_PP_EXPAND_IMPL(x)
#define STX_PP_EXPAND_IMPL(x) x

""")
write_header_guard_end(f, header_guard)

f = open(preprocessor_path + 'arithmetic.hpp', 'w')
header_guard = 'STX_PREPROCESSOR_ARITHMETIC_HPP'
write_header_guard_begin(f, header_guard)
f.write("""\
#include <stx/preprocessor/arithmetic/inc.hpp>
#include <stx/preprocessor/arithmetic/dec.hpp>

""")
write_header_guard_end(f, header_guard)

f = open(preprocessor_path + 'arithmetic/inc.hpp', 'a+')
header_guard = 'STX_PREPROCESSOR_ARITHMETIC_INC_HPP'
write_header_guard_begin(f, header_guard)

f.write('#define STX_PP_INC(x) STX_PP_CAT(STX_PP_INC_, x)\n\n')
for i in range(container_max_size):
    f.write('#define STX_PP_INC_{0} {1}\n'.format(i, i + 1))
f.write('\n')

write_header_guard_end(f, header_guard)

#-------------------------------------------------------------------------------

f = open(preprocessor_path + 'arithmetic/dec.hpp', 'a+')
header_guard = 'STX_PREPROCESSOR_ARITHMETIC_DEC_HPP'
write_header_guard_begin(f, header_guard)

f.write('#define STX_PP_DEC(x) STX_PP_CAT(STX_PP_DEC_, x)\n\n')
for i in range(1, container_max_size + 1):
    f.write('#define STX_PP_DEC_{0} {1}\n'.format(i, i - 1))
f.write('\n')

write_header_guard_end(f, header_guard)


f = open(preprocessor_file_name, 'a+')

if generate_STX_PP_FOR_EACH_i:
    f.write('/* STX_PP_FOR_EACH_i(macro, ...) */\n')
    f.write('/* macro(elem) */\n')
    for i in range (1, for_each_size + 1):
        f.write('#define STX_PP_FOR_EACH_{0}(macro'.format(i))
        for j in range(i):
            f.write(', a{0}'.format(j))
        f.write(') \\\n   ')
        for j in range(i):
            f.write(' macro(a{0})'.format(j))
            if j != i - 1: f.write(' \\\n   ')
        f.write('\n\n')

if generate_STX_PP_FOR_EACH_I_i:
    f.write('/* STX_PP_FOR_EACH_I_i(macro, ...) */\n')
    f.write('/* macro(elem, i) */\n')
    for i in range (1, for_each_size + 1):
        f.write('#define STX_PP_FOR_EACH_I_{0}(macro'.format(i))
        for j in range(i):
            f.write(', a{0}'.format(j))
        f.write(') \\\n   ')
        for j in range(i):
            f.write(' macro(a{0}, {1})'.format(j, j))
            if j != i - 1: f.write(' \\\n   ')
        f.write('\n\n')

#-------------------------------------------------------------------------------

f = open(preprocessor_path + 'seq.hpp', 'a+')
header_guard = 'STX_PREPROCESSOR_SEQ_HPP'
write_header_guard_begin(f, header_guard)
f.write("""\
#include <stx/preprocessor/seq/elem.hpp>
#include <stx/preprocessor/seq/for_each.hpp>
#include <stx/preprocessor/seq/for_each_i.hpp>
""")
for i in range(num_nested_seq_for_each_i):
    f.write("""\
#include <stx/preprocessor/seq/for_each_i_{0}.hpp>
""".format(i))
f.write("""\
#include <stx/preprocessor/seq/size.hpp>

""")
write_header_guard_end(f, header_guard)

f = open(preprocessor_path + 'seq/size.hpp', 'a+')
header_guard = 'STX_PREPROCESSOR_SEQ_SIZE_HPP'
write_header_guard_begin(f, header_guard)

f.write('#define STX_PP_SEQ_SIZE(seq) STX_PP_CAT(STX_PP_SEQ_SIZE_, STX_PP_SEQ_SIZE_0 seq)\n\n')

for i in range(sequence_max_size + 1):
    f.write('#define STX_PP_SEQ_SIZE_{0}(_) STX_PP_SEQ_SIZE_{1}\n'.format(i, i + 1))
f.write('\n')

for i in range(sequence_max_size + 1):
    f.write('#define STX_PP_SEQ_SIZE_STX_PP_SEQ_SIZE_{0} {0}\n'.format(i))
f.write('\n')

write_header_guard_end(f, header_guard)

f = open(preprocessor_path + 'seq/for_each.hpp', 'a+')
header_guard = 'STX_PREPROCESSOR_SEQ_FOR_EACH_HPP'
write_header_guard_begin(f, header_guard)

f.write("""\
#include <stx/preprocessor/seq/elem.hpp>
#include <stx/preprocessor/seq/size.hpp>

#define STX_PP_SEQ_FOR_EACH(macro, seq) \\
    STX_PP_CAT(STX_PP_SEQ_FOR_EACH_ITER_, STX_PP_SEQ_SIZE(seq)) (macro, seq)

""")

f.write('#define STX_PP_SEQ_FOR_EACH_ITER_0\n')
for i in range(1, sequence_max_size + 1):
    f.write('#define STX_PP_SEQ_FOR_EACH_ITER_{0}(macro, seq) '.format(i))
    if i != 1:
        f.write('STX_PP_SEQ_FOR_EACH_ITER_{0}(macro, seq) '.format(i - 1))
    f.write('macro(STX_PP_SEQ_ELEM({0}, seq))\n'.format(i - 1))
f.write('\n')

write_header_guard_end(f, header_guard)

#-------------------------------------------------------------------------------
#   STX_PP_SEQ_FOR_EACH_I
#-------------------------------------------------------------------------------

def generate_seq_for_each_i(suffix = ''):
    f = open(preprocessor_path + 'seq/for_each_i{0}.hpp'.format(suffix), 'a+')
    header_guard = 'STX_PREPROCESSOR_SEQ_FOR_EACH_I{0}_HPP'.format(suffix)
    write_header_guard_begin(f, header_guard)
    f.write("""\
#include <stx/preprocessor/seq/elem.hpp>
#include <stx/preprocessor/seq/size.hpp>

#define STX_PP_SEQ_FOR_EACH_I{0}(macro, seq) \\
    STX_PP_CAT(STX_PP_SEQ_FOR_EACH_ITER_I{0}_, STX_PP_SEQ_SIZE(seq)) (macro, seq)

""".format(suffix))

    f.write('#define STX_PP_SEQ_FOR_EACH_ITER_I{0}_0\n'.format(suffix))
    for i in range(1, sequence_max_size + 1):
        f.write('#define STX_PP_SEQ_FOR_EACH_ITER_I{0}_{1}(macro, seq) '.format(suffix, i))
        if i != 1:
            f.write('STX_PP_SEQ_FOR_EACH_ITER_I{0}_{1}(macro, seq) '.format(suffix, i - 1))
        f.write('macro(STX_PP_SEQ_ELEM({0}, seq), {0})\n'.format(i - 1))
    f.write('\n')
    write_header_guard_end(f, header_guard)

generate_seq_for_each_i()

#-------------------------------------------------------------------------------
#   STX_PP_SEQ_FOR_EACH_I_i
#-------------------------------------------------------------------------------

for i in range(num_nested_seq_for_each_i):
    generate_seq_for_each_i('_' + str(i))

#-------------------------------------------------------------------------------
#   STX_PP_SEQ_ELEM
#-------------------------------------------------------------------------------

f = open(preprocessor_path + 'seq/elem.hpp', 'a+')
header_guard = 'STX_PREPROCESSOR_SEQ_ELEM_HPP'
write_header_guard_begin(f, header_guard)

f.write("""\
#define STX_PP_SEQ_ELEM(i, seq) STX_PP_SEQ_ELEM_IMPL1(i, seq)
#define STX_PP_SEQ_ELEM_IMPL1(i, seq) STX_PP_SEQ_ELEM_IMPL2(STX_PP_SEQ_ELEM_ ## i seq)
#define STX_PP_SEQ_ELEM_IMPL2(im) STX_PP_SEQ_ELEM_IMPL3(im)
#define STX_PP_SEQ_ELEM_IMPL3(x, _) x

""")

f.write('#define STX_PP_SEQ_ELEM_0(x) x, STX_PP_NOT_DEFINED\n')
for i in range(1, sequence_max_size + 1):
    f.write('#define STX_PP_SEQ_ELEM_{0}(_) STX_PP_SEQ_ELEM_{1}\n'.format(i, i - 1))
f.write('\n')

write_header_guard_end(f, header_guard)

#-------------------------------------------------------------------------------
#   STX_PP_TUPLE_REM
#-------------------------------------------------------------------------------

f = open(preprocessor_path + 'tuple.hpp', 'a+')
header_guard = 'STX_PREPROCESSOR_TUPLE_HPP'
write_header_guard_begin(f, header_guard)
f.write("""\
#include <stx/preprocessor/tuple/elem.hpp>
#include <stx/preprocessor/tuple/rem.hpp>

""")
write_header_guard_end(f, header_guard)

f = open(preprocessor_path + 'tuple/rem.hpp', 'a+')
header_guard = 'STX_PREPROCESSOR_TUPLE_REM_HPP'
write_header_guard_begin(f, header_guard)

f.write('#define STX_PP_TUPLE_REM(size) STX_PP_TUPLE_REM_IMPL(size)\n')
f.write('#define STX_PP_TUPLE_REM_IMPL(size) STX_PP_TUPLE_REM_ ## size\n')
f.write('#define STX_PP_TUPLE_REM_0()\n')
num_tuple_rem = 32
for i in range(1, num_tuple_rem + 1):
    f.write('#define STX_PP_TUPLE_REM_{0}('.format(i))
    f.write('x0')
    for j in range(1, i):
        f.write(', x{0}'.format(j))
    f.write(') ')
    f.write('x0')
    for j in range(1, i):
        f.write(', x{0}'.format(j))
    f.write('\n')
f.write('\n')

write_header_guard_end(f, header_guard)

#-------------------------------------------------------------------------------
#   STX_PP_TUPLE_ELEM
#-------------------------------------------------------------------------------

f = open(preprocessor_path + 'tuple/elem.hpp', 'a+')
header_guard = 'STX_PREPROCESSOR_TUPLE_ELEM_HPP'
write_header_guard_begin(f, header_guard)

f.write('#define STX_PP_TUPLE_ELEM(size, index, tuple) STX_PP_TUPLE_ELEM_I(size, index, tuple)\n')
f.write('#define STX_PP_TUPLE_ELEM_I(s, i, t) STX_PP_TUPLE_ELEM_ ## s ## _ ## i t\n')
num_tuple_elem = 32
for i in range(1, num_tuple_elem + 1):
    for j in range(i):
        f.write('#define STX_PP_TUPLE_ELEM_{0}_{1}('.format(i, j))
        f.write('x0')
        for k in range(1, i):
            f.write(', x{0}'.format(k))
        f.write(') ')
        f.write('x{0}'.format(j))
        f.write('\n')
f.write('\n')

write_header_guard_end(f, header_guard)

f = open(preprocessor_file_name, 'a+')
write_header_guard_end(f, main_header_guard)
